﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace AutomatedTP
{
    /// <summary>
    /// <see cref="Writer"/> class 
    /// </summary>
    public class Writer
    {
        private string proc_name;
        private bool wrap_b = false;
        //predefined functions - always same header
        private Func main_f;        
        private Func rule_set;
        private Func run_test;
        private string module;

        /// <summary>
        /// Initializes a new instance of the <see cref="Writer"/> class.
        /// </summary>
        /// <param name="proc_name">Define name of generated test procedure. This name would be use for file name of this procedure.</param>
        public Writer(string proc_name)
        {
            this.proc_name = proc_name;
            Dictionary<string, string> input = new Dictionary<string,string>();
            input.Add("cppca_sut", "char*");
            input.Add("cppca_context", "char*");
            main_f = new Func("main", null, "!END_SCRIPT(true)", "int", 0, null);
            rule_set = new Func("rule_set", "static", null, "void", 2, input);
            run_test = new Func("run_tests", "static", null, "void", 0, null);
        }

        /// <summary>
        /// Print_descriptions print descriptions about defined function into test procedure.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="function">The function parameter define function to be printed.</param>
        /// <param name="description">The description will be added to comlet description.</param>
        public void print_description(StreamWriter file, Func function, string description)
        {
            //file.WriteLine("/* ******************************************************************");
            start_comment(file, '*');
            file.WriteLine(" * Description:");
            file.WriteLine(" *   " + function.name + "() - " + description);
            file.WriteLine(" * Parameters:");
            if (function.GetInput().Count == 0)
            {
                file.WriteLine(" *   none");
            }
            else
            {
                foreach (var param in function.GetInput())
                {
                    file.WriteLine(" *  " + param.Value + " " + param.Key );
                }
            }

            file.WriteLine(" * returns:");
            if (function is Wrap)
            {
                if (function.name.Contains("BEFORE"))
                {
                    file.WriteLine(" *    return 1 to call real function followed by AFTER function");
                    file.WriteLine(" *    return 0 to call REPLACE function only.");
                }
                if (function.name.Contains("AFTER"))
                {
                    file.WriteLine(" *    return value from wrapped function");
                }
                if (function.name.Contains("REPLACE"))
                {
                    file.WriteLine(" *    default zero if REPLACE wrap is not used");
                }                
            }
            else
            {
                if (function.ret_type == null)
                {
                    file.WriteLine(" *   none");
                }
                else
                {
                    file.WriteLine(" *   " + function.ret_type);
                }
            }            
            end_comment(file, '*');
        }

        /// <summary>
        /// Print_fillers print fille between logilac code blocks.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="text">The text thath will be printed as comment.</param>
        public void print_filler(StreamWriter file, String text)
        {
            file.WriteLine();
            start_comment(file, '=');
            file.WriteLine(" * " + text);
            end_comment(file, '=');
        }
        
        /// <summary>
        /// This function print whole linked function.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="function">Link to function information.</param>
        /// <param name="data">The data should contains specific information for each type of printed function.
        /// But data[0] always should contain description of printed function!</param>
        public void print_function(StreamWriter file, Func function, TP data)
        {
            /// Depending of function type differen function body will be printed
            switch (function.name)
            {
                case "main":
                    print_main_body(file, data);
                    break;
                case "rule_set":
                    print_rule_set_body(file, data);
                    break;
                case "run_tests":
                    print_run_tests_body(file, data);
                    break;
                default:                    
                    Logger.WriteToLog(3, "Default name of function to print!");
                    break;
            }
            
            if (!(function.ret_type == null || function.ret_type.Equals("void")))
            {
                file.WriteLine("  return " + function.ret_val + ";");
            }
            file.WriteLine("}");
            file.WriteLine();
        }

        /// <summary>
        /// Print function header to the specified file.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="function">Link to function information.</param>
        /// <param name="end">if set to <c>true</c> [end] will add semi-colon character after line.</param>
        public void print_func_header(StreamWriter file, Func function, bool end)
        {
            string input = "";
            if (function.num_of_param == 0)
            {
                string tmp = "";
                input = tmp;
            }
            else
            {
                int cnt = 0;
                foreach (var pair in function.GetInput())
                {
                    if (cnt > 0)
                    {
                        input += ", ";
                    }
                    //this sequence because keys shall be different
                    if (pair.Value == null)
                        input += pair.Key;
                    else
                        input += pair.Value + " " + pair.Key;                    
                    cnt++;
                }                
            }

            string type = "";
            if (function.func_type != null)
            {
                //add same for wraps!!!
                if (!(function.func_type.Equals("stub") | function.func_type.Equals("wrap")))
                { 
                    type = function.func_type + " "; 
                }
            }
            else
            {
                type = "";
            }
            string r_type;
            if (function.ret_type != null)
            {
                r_type = function.ret_type + " ";
            }
            else
            {
                r_type = "void ";
            }
            //; not usable in unction header with body!
            string ending = "";
            if (end) { ending += ";"; }
            file.WriteLine(type + r_type + function.name + "(" + input + ")"+ ending);
        }

        /// <summary>
        /// Print body of main function into the specified file.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="data">The data of whole test procedure stored in <see cref="TP"/> class.</param>
        public void print_main_body(StreamWriter file, TP data)
        {
            string desc = "Program entry point";
            string name = data.GetName();
            //string module = data.GetModule();

            print_description(file, main_f, desc);
            print_func_header(file, main_f, false);
            file.WriteLine("{");

            //handle default values if data is null or empty or just few.
            file.WriteLine("  char  block[12000];");
            file.WriteLine("  INIT_MEMORY_POOL((void*)&block, 12000);");
            file.WriteLine();
            file.WriteLine("  CONFIGURE_COVERAGE(\"cov:boolcomb:yes\");");
            file.WriteLine();
            file.WriteLine("  OPEN_LOG(\"\", false);");
            file.WriteLine("  SET_LOG_LEVEL(cppth_ll_normal);");
            file.WriteLine();
            file.WriteLine("  WRITE_TEST_HEADER(\"" + name + "\",\"" + module + ".c\");");
            file.WriteLine("  START_SCRIPT(\"" + name + "\",true);");
            file.WriteLine();
            file.WriteLine("  run_tests();");
            file.WriteLine("  REPORT_MEMORY_POOL();");
        }

        /// <summary>
        /// Print rules set bodies for test procedure to the specified file.
        /// </summary>
        /// <param name="file">File defined as stream output.</param>
        /// <param name="data">The data.</param>
        public void print_rule_set_body(StreamWriter file, TP data)
        {
            //handle for all analysis levels and find out id one value is enought
            double[] coverage = new double[4]{100.0, 100.0, 100.0, 100.0};
            if (data.GetAnalysis_level() == 'B')
            {
                coverage[3] = 0.0;
            }
            if (data.GetAnalysis_level() == 'C')
            {
                coverage[3] = 0.0;
                coverage[2] = 0.0;
            }
            if (data.GetAnalysis_level() == 'D')
            {
                coverage[3] = 0.0;
                coverage[2] = 0.0;
                coverage[1] = 0.0;
            }

            string desc = coverage + "% statement coverage + Decision coverage";           

            print_description(file, rule_set, desc);
            print_func_header(file, rule_set, false);
            file.WriteLine("{");

            //double coverage = double.Parse(data[1]);
            file.WriteLine("  ANALYSIS_CHECK(\""+coverage[0]+"% Entry Point Coverage\",");
            file.WriteLine("          cppca_entrypoint_cov,");
            file.WriteLine("          "+coverage[0]+");");
            file.WriteLine();
            file.WriteLine("  ANALYSIS_CHECK(\"" + coverage[1] + "% Statement Coverage\",");
            file.WriteLine("          cppca_statement_cov,");
            file.WriteLine("          " + coverage[1] + ");");
            file.WriteLine();
            file.WriteLine("  ANALYSIS_CHECK(\"" + coverage[2] + "% Decision Coverage\",");
            file.WriteLine("          cppca_decision_cov,");
            file.WriteLine("          " + coverage[2] + ");");
            file.WriteLine();
            file.WriteLine("  ANALYSIS_CHECK(\"" + coverage[3] + "% Boolean Operator Coverage\",");
            file.WriteLine("          cppca_booloper_cov,");
            file.WriteLine("          " + coverage[3] + ");");
            file.WriteLine();
            file.WriteLine("  REPORT_COVERAGE(cppca_entrypoint_cov|");
            file.WriteLine("        cppca_statement_cov|");
            file.WriteLine("        cppca_decision_cov|");
            file.WriteLine("        cppca_booloper_cov,");
            file.WriteLine("        cppca_sut,");
            file.WriteLine("        cppca_all_details|cppca_include_catch,");
            file.WriteLine("        cppca_context);");
        }
        
        /// <summary>
        /// Print_run_tests_bodies the specified file.
        /// Name of function should not contain dot '.' because intern parsing.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="data">The data.</param>
        public void print_run_tests_body(StreamWriter file, TP data)
        {
            string desc = "Test control: contains calls to the individual test cases";
            print_description(file, run_test, desc);
            print_func_header(file, run_test, false);
            file.WriteLine("{");

            int cnt = 1;
            foreach (var tc_tmp in data.GetTC())
            {
                file.WriteLine("  /* <" + tc_tmp.GetName() + "/> */");                
                string name = toFunc(data.GetName().ToLower()) + "_" + cnt;
                file.WriteLine("  " + name + "();");

                cnt++;
            }

            file.WriteLine();
            file.WriteLine("  #ifndef COVERAGE_OFF");
            file.WriteLine("  /* Functions under test */");
                        
            //Problem if tested function is also local function!
            List<string> f_under = new List<string>();
            foreach(var tmp in data.GetTC())
            {
                string tmp_name = tmp.GetProc().tested_func;
                if(!f_under.Contains(tmp_name))
                {
                    f_under.Add(tmp_name);
                }
            }
            foreach (String glob_name in f_under)
            {
                file.WriteLine("    rule_set(\"" + glob_name + "\", \"*\");");
            }

            //Set all other functions that can be called within tested module for code coverage (maybe we should add wraps too)
            file.WriteLine("  /* Other functions */");
            string[] loc_func = new string[]{"!","!","!"};
                //global_var.XML_module.Element("module").Element("local_func").Elements("name");
            foreach (var xe_tmp in data.GetLfunc())
            {
                file.WriteLine("    rule_set(\"" + xe_tmp.name + "\", \"*\");");
            }

            file.WriteLine("  EXPORT_COVERAGE(\"\", cppca_export_replace);");
            file.WriteLine("  #endif");

        }

        /// <summary>
        /// Print_wraps to the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="wrap">The wrap.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_wraps(StreamWriter file, Wrap wrap, TP tp_one)
        {
            Wrap before = new Wrap("BEFORE_" + wrap.name, "i16_call_orig", "INT16", wrap.num_of_param, wrap.GetInput());
            print_description(file, before, "Before wrap for this function.");
            print_func_header(file, before, false);
            print_before_wrap(file, wrap, tp_one);

            Dictionary<string, string> input = new Dictionary<string, string>();
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            if (wrap.ret_type != null)
            {
                //maybe parametrize ret_val asi string or variable!
                input.Add("ret_val", wrap.ret_type);
            }
            else
            { 
                //cppsm_void_return = void
                input.Add("cppsm_void_return", null);
            }
            Wrap after = new Wrap("AFTER_" + wrap.name, null, wrap.ret_type, input.Count, input);
            print_description(file, after, "After wrap for this function.");
            print_func_header(file, after, false);
            print_after_wrap(file, wrap, tp_one);

            Wrap replace = new Wrap("REPLACE_" + wrap.name, wrap.ret_val, wrap.ret_type, wrap.num_of_param, wrap.GetInput());
            print_description(file, replace, "Replace wrap for this function");
            print_func_header(file, replace, false);
            print_replace_wrap(file, wrap, tp_one);
        }

        /// <summary>
        /// Print_replace_wraps the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="wrap">The wrap.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_replace_wrap(StreamWriter file, Wrap wrap, TP tp_one)
        {
            file.WriteLine("{");
            if (wrap.ret_type != null)
                file.WriteLine("  " + wrap.ret_type + " ret_val = 0;");
            
            print_operations(file, wrap, wrap.GetReplace());
            
            if (wrap.ret_type != null)
                file.WriteLine("  return(ret_val)");
            file.WriteLine("}");
        }

        /// <summary>
        /// Print_after_wraps the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="wrap">The wrap.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_after_wrap(StreamWriter file, Wrap wrap, TP tp_one)
        {
            file.WriteLine("{");
            print_operations(file, wrap, wrap.GetAfter());
            if (wrap.ret_type != null)
                file.WriteLine("  return(ret_val)");
            file.WriteLine("}");
        }

        /// <summary>
        /// Print_before_wraps the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="wrap">The wrap.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_before_wrap(StreamWriter file, Wrap wrap, TP tp_one)
        {
            file.WriteLine("{");
            file.WriteLine("  /* Call original function */");
                                
            string orig = "";
            if (wrap.orig_call)
            {
                orig += "CALL_ORIG_FUNCTION";
            }
            else
            {
                //find out the name of the macro!!!
                orig += "CALL_REPL_FUNCTION";
            }

            file.WriteLine("  INT16 i16_call_orig = " + orig + ";");
            file.WriteLine();
            foreach (var cnt in tp_one.GetCounters())
            {
                if (cnt.Contains(wrap.name))
                {
                    file.WriteLine("  " + cnt + "++;");
                    file.WriteLine();
                }
            }
            file.WriteLine("  /* Register call */");
            file.WriteLine("  REGISTER_CALL(\"" + wrap.name + "\");");

            //handle all operations like in stub!!!
            print_operations(file, wrap, wrap.GetBefore());

            file.WriteLine("  return (i16_call_orig);");
            file.WriteLine();
            file.WriteLine("}");
        }
        
        /// <summary>
        /// Print_stubs the specified file.
        /// Link to tp is here just for global counters
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="stub">The stub.</param>
        /// <param name="tp">The tp.</param>
        public void print_stub(StreamWriter file, Stub stub, TP tp)
        {
            bool ret = false;
            Variable ret_val = new Variable();            
            print_description(file, stub, "Stub for this function ");
            print_func_header(file, stub, false);
            file.WriteLine("{");

            if (stub.ret_type != null)
            {
                ret = true;
                ret_val.type = stub.ret_type;
                ret_val.name = "ret_val";
                switch (ret_val.type)
                {
                    case "BOOL":
                        ret_val.value = "FALSE";
                        break;
                    default:
                        ret_val.value = "0";
                        break;
                }
                file.WriteLine("  " +ret_val.type + " " + ret_val.name + " = " + ret_val.value + ";");
            }
            foreach(var cnt in tp.GetCounters())
            {
                if(cnt.Contains(stub.name))
                {
                    file.WriteLine("  " + cnt + "++;");
                    file.WriteLine();
                }
            }            

            //sometimes we should be able to turn this off!!!            
            file.WriteLine("  /* Register call */");
            file.WriteLine("  REGISTER_CALL(\"" + stub.name + "\");");
            
            //file.WriteLine("  WRITE_LOG("<FMPC-LTC-42.4.1/> \n", cppth_ll_normal, false);");

            print_operations(file, stub, stub.GetOps());

            if (ret)
                file.WriteLine("  return(" + ret_val.name + ");");
            file.WriteLine("}");
        }      

        /// <summary>
        /// Print_tprocs the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="function">The function.</param>
        /// <param name="data">The data is tproc.</param>
        /// <param name="tp_one">The tp_one.</param>
        public void print_tproc(StreamWriter file, Func function, TC data, TP tp_one)
        {         
            Tproc t_proc = data.GetProc();
            print_description(file, function, "LTC: " + data.GetName());

            file.WriteLine("static void " + function.name + "()");
            file.WriteLine("{");

            file.WriteLine("  /* 1. LOCAL AUXILIARY VARIABLES */");
            //initialize all global counters!!! thats why we need tp_one || maube different section
            if (tp_one.GetCounters().Count > 0)
            {
                foreach(var counter in tp_one.GetCounters())
                {
                    file.WriteLine("  " + counter + " = 0;");
                }                
            }
            else {
                file.WriteLine("  /* none */");
            }            
            file.WriteLine();
            //some counters or conditions about run
            
            file.WriteLine("  /* 2. VARIABLES FOR INPUTS */");
            //plus tested function input parameters!!!
            if (t_proc.GetInitGlobVar() == null)
            { file.WriteLine("  /* none */"); }
            foreach (var tmp in t_proc.GetInitGlobVar())
            {
                switch (tmp.form)
                {
                        //Add other formats if new will be generated!
                    case "var":
                        file.Write("  ");
                        print_globvar_set(file, tmp);
                        break;
                    case "reg":
                        file.Write("  ");
                        print_reg_set(file, tmp);
                        break;
                    case "lvar":
                        file.Write("  ");
                        print_reg_set(file, tmp);
                        break;
                    case "gvar":
                        file.Write("  ");
                        print_globvar_set(file, tmp);
                        break;
                    default:
                        Logger.WriteToLog(3, "Bad form of variable for initialization: " + tmp.name); 
                        break;
                }
            }
            file.WriteLine();
            file.WriteLine("  /* 3. VARIABLES FOR ACTUAL OUTPUTS */");
            if (t_proc.GetRetVal() != null)
            {
                file.WriteLine("  " + t_proc.GetRetVal().type + " " + t_proc.GetRetVal().name + ";");
            }
            else 
            {
                file.WriteLine("  /* none */");
            }
            file.WriteLine();

            file.WriteLine("  /* 4. SETTING OF CONDITIONS */");
            file.WriteLine("  /* none */");
            file.WriteLine();

            file.WriteLine("  /* 5. TEST DESCRIPTION */");
            file.WriteLine("  START_TEST(\"_1\",\"\");");
            file.WriteLine();

            file.WriteLine("  /* 6. TESTING */");
            file.WriteLine("  /* none */");
            file.WriteLine();

            file.WriteLine("  /* Expected Call Sequence  */");
            var call_seq = data.GetProc().GetSequence();                          
            if (call_seq.Count() > 0)
            {
                //defined order (;) or not defined (&)!
                char order;
                if(data.GetProc().defined_order)
                    order = ';';
                else
                    order = '&';

                int counter = 1;
                file.Write("  EXPECTED_CALLS(");
                foreach (var call in call_seq)
                {                    
                    string start = "";
                    if (call.Value > 1)
                    {
                        start = call.Value + "*";
                    }                                        
                    if (counter > 1)
                    {
                        file.Write("          ");
                    }
                    string end = "";
                    if (counter == call_seq.Count())
                        { end += ");"; }
                    file.WriteLine("\"" + start + call.Key + "#" + name_cut(data.GetName()) + order + "\"" + end);
                    counter++;                    
                }
            }
            else
            {
                file.WriteLine("  EXPECTED_CALLS();");
            }
            file.WriteLine();

            file.WriteLine("  /* Call function under test */");
            file.WriteLine("  if(!setjmp(buf))");
            file.WriteLine("  {");
            file.WriteLine("    /* Call function under test */");
                   
            string ret = "";
            if (t_proc.GetRetVal() != null)
            {
                ret += t_proc.GetRetVal().name +" = ";
            }
            //tested function inputs .. should be same as global inputs variable (local) if problem!?!
            string input = "";
            var glob_func = global_var.XML_module.Element("module").Elements("global_func");
            foreach(var func in glob_func)
            {
                string tested_func = data.GetProc().tested_func;
                //Logger.WriteToLog(6, func.Element("name").Value);
                if (func.Element("name").Value.Equals(tested_func))
                {
                    //Logger.WriteToLog(6, func.Element("func_param").Attribute("void").Value);
                    if (func.Element("func_param").Attribute("void").Value.Equals("false"))
                    {
                        int cnt = 0;
                        var func_param = func.Element("func_param").Elements("param");
                        foreach (var param in func_param)
                        {
                            if (cnt > 0)
                                input += ", ";
                            input += param.Value;
                            //Logger.WriteToLog(6, cnt +" "+ param.Value);
                            cnt++;
                        }
                    }
                    break;
                }
            }
            file.WriteLine("    " + ret + data.GetProc().tested_func + "(" + input + ");");
            file.WriteLine("  }");
            file.WriteLine();

            file.WriteLine("  /* Checks of expected outputs */");
            file.WriteLine("  /* <" + data.GetName() + "> */");
            file.WriteLine("  WRITE_LOG(\"\\n <" + data.GetName() + "> \\n\", cppth_ll_normal, false);");
            if (t_proc.GetRetVal() != null) 
            {                
                file.Write("  ");
                print_check(file, t_proc.GetRetVal());
            }
            foreach (var exp in data.GetProc().GetExpGlobVar())
            {
                file.Write("  ");
                print_check(file, exp);
            }

            file.WriteLine();
            file.WriteLine("  END_CALLS();");
            file.WriteLine("  END_TEST();");
            //}
            file.WriteLine("}");
        }

        /// <summary>
        /// Print_modifies operation to the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="variable">The variable.</param>
        private void print_modify(StreamWriter file, Variable variable)
        {
            string name = "";
            if (variable.form.Equals("gvar"))
            {
                name += "ACCESS_VARIABLE(" + module + ", " + variable.name + ")";
            }
            else
            {
                name += variable.name;
            }
            file.WriteLine(name + " = " + variable.value + ";");
        }

        /// <summary>
        /// Print_returns operation to the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="variable">The variable.</param>
        private void print_return(StreamWriter file, Variable variable)
        {
            string ret = "ret_val";
            file.WriteLine(ret + " = " + variable.value + ";");
        }

        /// <summary>
        /// Print_checks operation to the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="variable">The variable.</param>
        private void print_check(StreamWriter file, Variable variable)
        {            
            string check = "";
            string name = "";                      

            //TBD add more types!!!            
            switch (variable.type)
            {
                case "UNIT8":
                    check += "CHECK_U_INT";
                    break;
                case "CHAR *":
                    check += "CHECK_STRING";
                    break;
                default:
                    Logger.WriteToLog(3, "Undefined variable type!");
                    break;
            }
            if (variable.form.Equals("gvar"))
            {
                name += "ACCESS_VARIABLE(" + module + ", " + variable.name + ")";
            }
            else {
                name += variable.name;
            }

            if ( variable.range != null && !variable.range.Equals("0"))
            {
                file.WriteLine(check + "_RANGE(" + name + ", " + variable.value +" - "+ variable.range + ", " + variable.value +" + "+ variable.range + ");");
            }
            else
            {
                file.WriteLine(check + "(" + name + ", " + variable.value + ");");
            }
        }

        /// <summary>
        /// Print_globvar_sets the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tmp">The temporary.</param>
        private void print_globvar_set(StreamWriter file, Variable tmp)
        {
            file.WriteLine("ACCESS_VARIABLE(" + module + ", " + tmp.name + ") = " + tmp.value + ";");
        }

        /// <summary>
        /// Print_reg_sets the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tmp">The temporary.</param>
        private static void print_reg_set(StreamWriter file, Variable tmp)
        {
            file.WriteLine(tmp.name + " = " + tmp.value + ";");
        }

        /// <summary>
        /// Convert string to the function.
        /// </summary>
        /// <param name="module">The module.</param>
        /// <returns></returns>
        public String toFunc(String module)
        {
            StringBuilder sb = new StringBuilder(module);

            for (int i = 0; i < sb.Length; i++)
            {
                if (sb[i].Equals('-'))
                {
                    sb[i] = '_';
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Print_tps the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tp_one">The tp_one.</param>
        internal void print_tp(StreamWriter file, TP tp_one)
        {
            Logger.WriteToLog(2, "=======================");
            Logger.WriteToLog(2, "Writing proces started.");

            //extract basic info => wich files should be created and call adequate functions
            module = tp_one.GetModule();
            List<TC> list_tc = tp_one.GetTC();

            foreach(var tmp_tc in list_tc){
                if (tmp_tc.GetWraps().Count > 0)
                {
                    wrap_b = true;
                    Logger.WriteToLog(1, "Wrap function: different approach used.");
                }
            }

            print_header(file);
            print_traceability(file, tp_one);            
            print_definitions(file);
            print_includes(file);
            print_func_declaration(file, tp_one);
            print_access(file, tp_one);
            print_glob_var(file, tp_one);

            //Why is this pragma here and it is necessary
            file.WriteLine("\r\n/* pragma ipl cantata++ testscript start */");
            
            print_filler(file, "Global Function Implementation");
            print_function(file, main_f, tp_one);  
          
            print_filler(file, "Local Function Implementation");
            print_function(file, rule_set, tp_one);            
            print_function(file, run_test, tp_one);

            print_filler(file, "Test procedures");
            int i = 1;
            foreach (var tc_tmp in tp_one.GetTC())
            {
                string name = toFunc( tp_one.GetName().ToLower() ) + "_" + i;
                Func proc_func = new Func(name, "static", null, "void", 0, null);
                print_tproc(file, proc_func, tc_tmp, tp_one);
                i++;
            }

            print_filler(file, "Stubs");
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //problem when more TC 
            //merge vsetky stuby a wrapy do niakej novej TC 
            // staci vytvoritlist stubov pripadne wrapov ... alebo mat jednu celu tc na vsetky metadata!!!
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!     
            TC utc_stub = new TC();
            foreach (var tc in tp_one.GetTC())
            {
                foreach (var stub in tc.GetStubs())
                {
                    bool nw = true;
                    foreach (var tmp in utc_stub.GetStubs())
                    {
                        if (stub.name.Equals(tmp.name))
                        {
                            nw = false;
                            foreach (var op in stub.GetOps())
                            {
                                op.SetTrace(tc.GetName());
                                tmp.AddOp(op);
                            }
                            break;
                        }
                    }
                    if (nw)
                    {
                        foreach (var tmp in stub.GetOps())
                            tmp.SetTrace(tc.GetName());

                        utc_stub.AddStub(stub);
                    }                    
                    //print_stub(file, stub, tc, tp_one);
                } 
            }
            foreach(var tmp in utc_stub.GetStubs())
            {
                print_stub(file, tmp, tp_one);
            }
            
            print_filler(file, "Wraps");
            if (wrap_b)
            {
                TC tc_wrap = new TC();
                file.WriteLine("/* pragma ipl cantata++ ignore on */");
                foreach (var tc in tp_one.GetTC())
                {
                    foreach (var wrap in tc.GetWraps())
                    {
                        bool nw = true;
                        foreach (var tmp in tc_wrap.GetWraps())
                        {
                            if (wrap.name.Equals(tmp.name))
                            {
                                nw = false;
                                foreach (var op in wrap.GetBefore())
                                {
                                    op.SetTrace(tc.GetName());
                                    tmp.AddBefore(op);
                                }
                                foreach (var op in wrap.GetAfter())
                                {
                                    op.SetTrace(tc.GetName());
                                    tmp.AddAfter(op);
                                }
                                foreach (var op in wrap.GetReplace())
                                {
                                    op.SetTrace(tc.GetName());
                                    tmp.AddReplace(op);
                                }
                                break;
                            }
                        }
                        if (nw)
                        {
                            foreach (var tmp in wrap.GetBefore())
                                tmp.SetTrace(tc.GetName());
                            foreach (var tmp in wrap.GetAfter())
                                tmp.SetTrace(tc.GetName());
                            foreach (var tmp in wrap.GetReplace())
                                tmp.SetTrace(tc.GetName());

                            tc_wrap.AddWrap(wrap);
                        }                        
                    }
                }
                foreach (var tmp in tc_wrap.GetWraps())
                {
                    print_wraps(file, tmp, tp_one);
                }
            }            

            file.WriteLine();
            file.WriteLine("///* pragma ipl cantata++ testscript end */");

            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            //header = global definitions (macro), register redefinition

            //wrap, access function or variable
            //ipg.cop 
            //ipg_cc.cop

            //c source file

            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            
        }

        /// <summary>
        /// Print_glob_vars the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_glob_var(StreamWriter file, TP tp_one)
        {
            print_filler(file, "Global variables");
            file.WriteLine("/* Global counters */");
            foreach (var gcnt in tp_one.GetCounters())
            {
                string type = "INT16";
                file.WriteLine(type + " " + gcnt + " = 0;");
            }
            file.WriteLine();
            file.WriteLine("/* Fake registers */");


            foreach (var reg in filter_reg(tp_one.GetRegisters()))
            {
                file.WriteLine(reg.type + " " + reg.name + ";");
            }

            file.WriteLine();
            file.WriteLine("/* Variable for end of test. */");
            file.WriteLine("static jmp_buf buf");
        }

        /// <summary>
        /// Print_accesses the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_access(StreamWriter file, TP tp_one)
        {
            print_filler(file, "Access functions and variables");

            if (tp_one.GetGVar().Count == 0)
            {
                file.WriteLine("/* None */");
            }
            else
            {
                file.WriteLine("typedef struct " + module + "_av_struct");
                file.WriteLine("{");

                foreach (var gvar in tp_one.GetGVar())
                {
                    file.WriteLine("  " + gvar.type + "* ref_" + gvar.name + ";");
                }
                file.WriteLine();
                file.WriteLine("} " + module + "_av_struct;");
                file.WriteLine();
                file.WriteLine("extern " + module + "_av_struct av_" + module + ";");
            }
        }

        /// <summary>
        /// Print_func_declarations the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_func_declaration(StreamWriter file, TP tp_one)
        {
            print_filler(file, "Function Declaration");
            print_func_header(file, run_test, true);
            print_func_header(file, rule_set, true);
            int i = 1;
            foreach (var tc_tmp in tp_one.GetTC())
            {                
                string name = toFunc(tp_one.GetName().ToLower()) + "_" + i;
                Func func_tmp = new Func(name, "static", null, "void", 0, null);
                print_func_header(file, func_tmp, true);
                i++;
            }
        }

        /// <summary>
        /// Print_includeses the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        private void print_includes(StreamWriter file)
        {
            print_filler(file, "Includes");
            file.WriteLine("#include <cantpp.h>");
            file.WriteLine("#include <cpp_preinclude.h>");
            file.WriteLine("#include <setjmp.h>");
            file.WriteLine("#include \u0022" + module + ".h\u0022");
            file.WriteLine("#include \u0022..\\..\\config.h\u0022");
            
            if (wrap_b) 
            {
                file.WriteLine();
                file.WriteLine("/* Pragmas for wrapping */");
                file.WriteLine("#pragma ipl cantata++ sm wrapper_function_file");
                file.WriteLine("#pragma ipl cantata++ sm wrap off");
                file.WriteLine("#pragma ipl cantata++ sm wrap default");
            }
        }

        /// <summary>
        /// Print_definitionses the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        private void print_definitions(StreamWriter file)
        {
            print_filler(file, "Definitions");
            file.WriteLine("#define TEST_SCRIPT_GENERATOR 1 /* ANALYSIS_CHECK enable */");
            file.WriteLine("#define __" + module.ToUpper() + "_INTERNAL__");
        }

        /// <summary>
        /// Print_traceabilities the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="tp_one">The tp_one.</param>
        private void print_traceability(StreamWriter file, TP tp_one)
        {
            print_filler(file, "Traceability");
            //Maybe later add range of test procedure.
            file.WriteLine("/* Test Procedure:    Module      Test Case           ");
            int i = 1;
            foreach (var tc_tmp in tp_one.GetTC())
            {
                //Depending on final intern standards!!!
                string name = toFunc(tp_one.GetName().ToLower()) + "_" + i;
                file.WriteLine(" * " + name +"     " + tp_one.GetModule() + "      " + tc_tmp.GetName());
                i++;
            }
            file.WriteLine(" */");
        }
        
        /// <summary>
        /// Print_headers the specified file.
        /// In real usage there will be more information.
        /// </summary>
        /// <param name="file">The file.</param>
        private void print_header(StreamWriter file)
        {
            start_comment(file, '*');
            file.WriteLine(" * UNIS a.s.");
            file.WriteLine(" * Mechatronic systems");
            file.WriteLine(" * JUndrovska 33");
            file.WriteLine(" * Brno, Czech republic");
            file.WriteLine(" *");
            file.WriteLine(" * Project: 13FPEC2");
            file.WriteLine(" * ID of SW product: fmpc_ii_fmpctrl");
            end_comment(file, '*');
            //revision
        }

        /// <summary>
        /// Start_comments the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="filler">The filler.</param>
        private void start_comment(StreamWriter file, char filler)
        {
            file.WriteLine("/* " + new string(filler, 70));
        }

        /// <summary>
        /// End_comments the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="filler">The filler.</param>
        private void end_comment(StreamWriter file, char filler)
        {
            file.WriteLine(" * " + new string(filler, 70) + " */");
        }

        /// <summary>
        /// Cut name for first nine letters.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private string name_cut(string name)
        {
            return name.Remove(0, 9);
        }

        //

        /// <summary>
        /// Print_operationses the specified file.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="func">The function - func is there only for name of gobal counter
        /// instead of whole TP and problems with identify correct stub/wrap.</param>
        /// <param name="list">The list.</param>
        private void print_operations(StreamWriter file, Func func, List<Operation> list)
        {                      
            if (list.Count != 0)
            {
                var query =
                    from op in list
                    group op by op.GetTrace(); 
                
                foreach (var q in query)
                {
                    file.WriteLine();
                    file.WriteLine("  /* </" + q.Key + ">  */");
                    file.WriteLine("  IF_INSTANCE(\"" + name_cut(q.Key) + "\")");
                    file.WriteLine("  {");
                    foreach (var op in q)
                    {
                        if (op.instance == 0)
                        {
                            if (op is Check)
                            {
                                file.Write("    ");
                                print_check(file, op.GetVariable());
                            }
                            if (op is Return)
                            {
                                file.Write("    ");
                                print_return(file, op.GetVariable());
                            }
                            if (op is Modify)
                            {
                                file.Write("    ");
                                print_modify(file, op.GetVariable());
                            }
                        }
                        else
                        {
                            file.WriteLine("    /* </"+ op.instance +" instance call>  */");
                            file.WriteLine("    if(COUNTER_" + func.name + " == " + op.instance + ")");
                            file.WriteLine("    {");
                            if (op is Check)
                            {
                                file.Write("      ");
                                print_check(file, op.GetVariable());
                            }
                            if (op is Return)
                            {
                                file.Write("      ");
                                print_return(file, op.GetVariable());
                            }
                            if (op is Modify)
                            {
                                file.Write("      ");
                                print_modify(file, op.GetVariable());
                            }
                            file.WriteLine("    }");
                        }
                    }
                    file.WriteLine("  }");
                }
            }            
        }

        /// <summary>
        /// Print_headers the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="tp_one">The tp_one.</param>
        internal void print_header(string path, TP tp_one)
        {
            string include = Path.Combine(path, "include");
            Directory.CreateDirectory(include);
            string header = Path.Combine(include, "test.h");
            //((FileStream)(file.BaseStream)).Name;
            if (System.IO.File.Exists(header))
            {
                //Console.WriteLine("File exist!");
                Logger.WriteToLog(2, header);
                Logger.WriteToLog(2, "Header file for TP exist!");
            }
            else
            {
                //Console.WriteLine("File does not exist and will be created!");
                Logger.WriteToLog(3, "Header file for TP does not exist and will be created!");
                File.Create(header).Close();
            }

            using (StreamWriter file = new System.IO.StreamWriter(header))
            {
                print_header(file);
                print_filler(file, "Global definitions");
                file.WriteLine("#ifndef __TEST_H__");
                file.WriteLine("#define __TEST_H__");

                bool wrap = false;
                foreach (var tmp in tp_one.GetTC())
                {
                    if (tmp.GetWraps().Count != 0)
                    {
                        wrap = true;
                        break;
                    }
                }
                if (wrap)
                {
                    file.WriteLine("");
                    file.WriteLine("/* Wrap macro definition */");
                    file.WriteLine("#define CALL_ORIG_FUNCTION 1U");
                    file.WriteLine("#define CALL_REPL_FUNCTION 0U");
                }

                List<Variable> lst_tmp = filter_reg(tp_one.GetRegisters());


                if (lst_tmp.Count != 0)
                {
                    file.WriteLine();
                    file.WriteLine("/* Registers redefinition */");

                    foreach (var reg in lst_tmp)
                    {
                        file.WriteLine("#undef " + reg.name);
                    }
                    //file.WriteLine();
                    foreach (var reg in lst_tmp)
                    {
                        file.WriteLine("extern " + reg.type + " " + reg.name);
                    }
                }
                
                file.WriteLine();
                file.WriteLine("#endif");
            }
        }

        /// <summary>
        /// Filter registers.
        /// </summary>
        /// <param name="registers">The registers.</param>
        /// <returns></returns>
        private static List<Variable> filter_reg(List<Variable> registers)
        {
            List<Variable> lst_tmp = new List<Variable>();

            foreach (var reg in registers)
            {
                Variable tmp = reg;
                string[] words = reg.name.Split('.');
                tmp.name = words[0];
                if (!lst_tmp.Exists(t => t.name.Equals(tmp.name)))
                    lst_tmp.Add(tmp);
            }

            return lst_tmp;
        }

        /// <summary>
        /// Print information into ipg file by the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="tp_one">The tp_one.</param>
        internal void print_ipg(string path, TP tp_one)
        {
            string filename = Path.Combine(path, "ipg.cop");

            if (System.IO.File.Exists(filename))
            {
                //Console.WriteLine("File exist!");
                Logger.WriteToLog(2, filename);
                Logger.WriteToLog(2, "IPG file for TP exist!");
            }
            else
            {
                //Console.WriteLine("File does not exist and will be created!");
                Logger.WriteToLog(3, "IPG file for TP does not exist and will be created!");
                File.Create(filename).Close();
            }

            using (StreamWriter file = new System.IO.StreamWriter(filename))
            {
                file.WriteLine("#");
                file.WriteLine("# Cantata++ Options");
                file.WriteLine("#");
                file.WriteLine("# WARNING: Do not alter this file manually.");
                file.WriteLine("#");
                file.WriteLine("#tool.use=true");
                file.WriteLine("#old.dir=c:/");
                file.WriteLine("#new.dir=C:/");
                file.WriteLine("\"--analyse\"");
                file.WriteLine("\"--verbose\"");
                file.WriteLine("\"--parse:--line_directives\"");
                file.WriteLine("\"--parse:--trace_includes\"");
                file.WriteLine("\"--parse:-W2\"");
                
                foreach (var var in tp_one.GetGVar())
                {
                    file.WriteLine("\"--sm:--access_variable:\""+ module +".c\":"+ var.name +"\"");     
                }
                
                file.WriteLine("\"--sm:--call_seq_code\"");

                List<string> wraps = new List<string>();
                foreach (var tc in tp_one.GetTC())
                {
                    foreach (var wrap in tc.GetWraps())
                    {
                        if (!wraps.Exists(t => t.Equals(wrap.name)))
                        {
                            string input = extract_paramT(wrap);
                            wraps.Add(wrap.name);
                            file.WriteLine("\"--sm:--wrap:" + wrap.name + "("+input+")#*\"");
                        }                        
                    }
                }                               

                file.WriteLine("\"--comp:fmpc_ii_cantataconf_6.1.1\"");
            }
        }

        /// <summary>
        /// Extract params from wrap.
        /// </summary>
        /// <param name="wrap">The wrap.</param>
        /// <returns></returns>
        private static string extract_paramT(Wrap wrap)
        {
            string input = "";
            if (wrap.num_of_param != 0)
            {
                int cnt = 0;
                foreach (var pair in wrap.GetInput())
                {
                    if (cnt > 0)
                    {
                        input += ", ";
                    }
                    input += pair.Value;
                    cnt++;
                }
            }
            return input;
        }

        /// <summary>
        /// Print information into ipg_cc file for code coverage by the specified path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="tp_one">The tp_one.</param>
        internal void print_ipg_cc(string path, TP tp_one)
        {
            string filename = Path.Combine(path, "ipg_cc.cop");

            if (System.IO.File.Exists(filename))
            {
                //Console.WriteLine("File exist!");
                Logger.WriteToLog(2, filename);
                Logger.WriteToLog(2, "IPG_CC file for TP exist!");
            }
            else
            {
                //Console.WriteLine("File does not exist and will be created!");
                Logger.WriteToLog(3, "IPG_CC file for TP does not exist and will be created!");
                File.Create(filename).Close();
            }

            using (StreamWriter file = new System.IO.StreamWriter(filename))
            {
                file.WriteLine("#");
                file.WriteLine("# Cantata++ Options");
                file.WriteLine("#");
                file.WriteLine("# WARNING: Do not alter this file manually.");
                file.WriteLine("#");
                file.WriteLine("#tool.use=true");
                file.WriteLine("#old.dir=c:/");
                file.WriteLine("#new.dir=C:/");
                file.WriteLine("\"--analyse\"");
                file.WriteLine("\"--verbose\"");
                file.WriteLine("\"--ci:--instr:stmt;func;decn;log;\"");
                file.WriteLine("\"--parse:--line_directives\"");
                file.WriteLine("\"--parse:--trace_includes\"");
                file.WriteLine("\"--parse:-W2\"");

                foreach (var var in tp_one.GetGVar())
                {
                    file.WriteLine("\"--sm:--access_variable:\"" + module + ".c\":" + var.name + "\"");
                }

                file.WriteLine("\"--sm:--call_seq_code\"");

                List<string> wraps = new List<string>();
                foreach (var tc in tp_one.GetTC())
                {
                    foreach (var wrap in tc.GetWraps())
                    {
                        if (!wraps.Exists(t => t.Equals(wrap.name)))
                        {
                            string input = extract_paramT(wrap);
                            wraps.Add(wrap.name);
                            file.WriteLine("\"--sm:--wrap:" + wrap.name + "("+input+")#*\"");
                        }                        
                    }
                }

                file.WriteLine("\"--comp:fmpc_ii_cantataconf_6.1.1\"");
            }
        }
    }
}
